// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-05

package endpoint

import (
	"encoding/json"
	"gitee.com/gomq/sr/filter"
	"regexp"
	"strings"
	"time"
)

var (
	endpointMatchProtocol = regexp.MustCompile(`^([a-zA-Z0-9]+)://`)
	endpointTimeout       = time.Second * 10
)

type (
	Endpoint interface {
		GetAddress() Address
		GetFilter() (filter filter.Filter, has bool)
		GetFormat() filter.Format
		GetMethod() Method
		GetProtocol() Protocol
		GetTimeout() time.Duration

		// + Setter

		SetAddress(address Address) Endpoint
		SetFilter(filter filter.Filter) Endpoint
		SetFormat(format filter.Format) Endpoint
		SetMethod(method Method) Endpoint
		SetProtocol(protocol Protocol) Endpoint
		SetTimeout(seconds int) Endpoint
	}

	endpoint struct {
		Address   Address       `json:"Address,omitempty"`
		Filter    filter.Filter `json:"Filter,omitempty"`
		FilterHas bool          `json:"-"`
		Format    filter.Format `json:"Format,omitempty"`
		Method    Method        `json:"Method,omitempty"`
		Protocol  Protocol      `json:"Protocol,omitempty"`
		Timeout   time.Duration `json:"Timeout,omitempty"`
	}
)

func NewEndpoint() Endpoint { return (&endpoint{}).init() }

// + Getter

func (o *endpoint) GetAddress() Address              { return o.Address }
func (o *endpoint) GetFilter() (filter.Filter, bool) { return o.Filter, o.FilterHas }
func (o *endpoint) GetFormat() filter.Format         { return o.Format }
func (o *endpoint) GetMethod() Method                { return o.Method }
func (o *endpoint) GetProtocol() Protocol            { return o.Protocol }
func (o *endpoint) GetTimeout() time.Duration        { return o.Timeout }

// + Setter

func (o *endpoint) SetAddress(address Address) Endpoint {
	if address.Undefined() {
		return o
	}

	o.Address = address

	if m := endpointMatchProtocol.FindStringSubmatch(address.String()); len(m) == 2 {
		if s := strings.TrimSpace(m[1]); s != "" {
			o.Protocol = Protocol(s).Lower()
		}
	}
	return o
}

func (o *endpoint) SetFilter(filter filter.Filter) Endpoint {
	o.Filter = filter
	o.FilterHas = filter != nil
	return o
}

func (o *endpoint) SetFormat(format filter.Format) Endpoint {
	if format.Undefined() {
		return o
	}

	o.Format = format

	if o.Protocol.IsHttp() || o.Protocol.IsHttps() {
		o.Format = format.Upper()
	}
	return o
}

func (o *endpoint) SetMethod(method Method) Endpoint {
	if method.Undefined() {
		return o
	}

	o.Method = method

	if o.Protocol.IsHttp() || o.Protocol.IsHttps() {
		o.Method = method.Upper()
	}
	return o
}

func (o *endpoint) SetProtocol(protocol Protocol) Endpoint {
	if !protocol.Undefined() {
		o.Protocol = protocol
	}
	return o
}

func (o *endpoint) SetTimeout(seconds int) Endpoint {
	if seconds > 0 {
		o.Timeout = time.Second * time.Duration(seconds)
	}
	return o
}

// + Common

func (o *endpoint) String() string {
	if buf, err := json.Marshal(o); err == nil {
		return string(buf)
	}
	return ""
}

// + Access methods

func (o *endpoint) init() *endpoint {
	o.Method = MethodPost
	o.Protocol = ProtocolHttp
	o.Timeout = endpointTimeout
	return o
}
